package xyz.archknight.app.loginput.dictionary.gen.ui

import xyz.archknight.app.loginput.dictionary.gen.service.EventBus
import java.awt.*
import java.awt.datatransfer.DataFlavor
import java.awt.datatransfer.StringSelection
import java.awt.dnd.DnDConstants
import java.awt.dnd.DragGestureEvent
import java.awt.dnd.DragGestureListener
import java.awt.dnd.DragSource
import javax.swing.*


/**
 * 合并多个来自缓存区词汇的合并对话框
 *
 * @author midnite
 * create at 2020-06-22 10:22 下午
 */
class MergeDialog(owner: JFrame, private val phases: Array<String>) : JDialog(owner) {
    private val phaseList = JList<String>()
    private val sortPane = JScrollPane(phaseList)
    private val preview = JLabel(phases.joinToString(""))
    private val operatePane = JPanel()
    private val cancelButton = JButton("取消合并")
    private val assembleButton = JButton("合并词汇")

    init {
        createUI()
    }

    private fun createUI() {
        size = Dimension(400, 320)
        title = "词汇合并"
        contentPane = JPanel().apply {
            border = BorderFactory.createEmptyBorder(8, 8, 8, 8)
        }

        with(operatePane) {
            layout = FlowLayout(FlowLayout.RIGHT)
            add(assembleButton)
            add(cancelButton)
        }

        val centerPane = JPanel().apply {
            layout = GridBagLayout()
            val constraints = GridBagConstraints()
            constraints.fill = GridBagConstraints.BOTH
            constraints.gridwidth = GridBagConstraints.REMAINDER
            constraints.weighty = 1.0
            constraints.weightx = 1.0
            add(sortPane, constraints)
            constraints.weighty = 0.0
            add(JLabel("合并预览").apply {
                border = BorderFactory.createEmptyBorder(8, 0, 8, 0)
            }, constraints)
            add(preview, constraints)
        }

        with(contentPane) {
            layout = BorderLayout(8, 8)
            add(JLabel("请调整以下词汇的组合顺序"), BorderLayout.NORTH)
            add(centerPane, BorderLayout.CENTER)
            add(operatePane, BorderLayout.SOUTH)
        }

        with(phaseList) {
            model = DefaultListModel<String>().apply {
                phases.forEach { addElement(it) }
            }
            dragEnabled = true
            dropMode = DropMode.INSERT
            transferHandler = DropHander(this, preview)
            DragListener(this)
        }

        cancelButton.addActionListener { isVisible = false }
        assembleButton.addActionListener {
            val assembleResult = (phaseList.model as DefaultListModel<String>).elements().toList().joinToString("")
            EventBus.assemble(assembleResult)
            isVisible = false
        }

        modalityType = ModalityType.APPLICATION_MODAL
        setLocationRelativeTo(null)
    }
}

class DragListener(private val list: JList<String>) : DragGestureListener {
    private val source = DragSource()
    private val recognizer = source.createDefaultDragGestureRecognizer(list, DnDConstants.ACTION_MOVE, this)

    override fun dragGestureRecognized(dge: DragGestureEvent?) {
        val transferable = StringSelection(list.selectedIndex.toString())
        source.startDrag(dge, DragSource.DefaultMoveDrop, transferable, null)
    }
}

class DropHander(
    private val list: JList<String>,
    private val preview: JLabel
) : TransferHandler() {
    override fun canImport(support: TransferSupport?): Boolean {
        if (support != null) {
            if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
                return false
            }
            val dl = support.dropLocation as JList.DropLocation
            return dl.index != -1
        }
        return false
    }

    override fun importData(support: TransferSupport?): Boolean {
        if (support != null) {
            if (!canImport(support)) {
                return false
            }
            val transferable = support.transferable
            return try {
                val transferFromIndex = Integer.parseInt(transferable.getTransferData(DataFlavor.stringFlavor) as String)
                val dl = support.dropLocation as JList.DropLocation
                val dropTargetIndex = dl.index
                val model = list.model as DefaultListModel<String>
                val transferData = model[transferFromIndex]
                model.remove(transferFromIndex)
                if (dropTargetIndex >= model.size) {
                    model.addElement(transferData)
                } else {
                    model.insertElementAt(transferData, dropTargetIndex)
                }
                preview.text = model.elements().toList().joinToString("")
                true
            } catch (e: Exception) {
                e.printStackTrace()
                false
            }
        }
        return false
    }
}